#include <cstdio>
#include <string>
#include <iostream>
#include <sstream>
#include <fstream>
#include <openssl/sha.h> // add opensll/sha to support sha256
#include <openssl/evp.h>
#include <chrono>

std::string calc_hash_of_data_with_sha256(std::string data)
{
    char buf[3];
    unsigned char hash[SHA256_DIGEST_LENGTH];
    SHA256_CTX sha256;
    SHA256_Init(&sha256);
    SHA256_Update(&sha256, data.c_str(), data.size());
    SHA256_Final(hash, &sha256);
    std::string NewString = "";
    for (int i = 0; i < SHA256_DIGEST_LENGTH; i++)
    {
        snprintf(buf, 3, "%02x", hash[i]);
        NewString = NewString + buf;
    }
    return NewString;
}

std::string calc_hash_of_data_with_evp_sha256(std::string data)
{
    char buf[3];
    unsigned int len = data.size();
    unsigned char hash[SHA256_DIGEST_LENGTH];
    EVP_MD_CTX * evpCtx = EVP_MD_CTX_new();
    EVP_DigestInit_ex(evpCtx, EVP_sha256(), NULL);
    EVP_DigestUpdate(evpCtx, data.c_str(), data.size());
    EVP_DigestFinal_ex(evpCtx, hash, &len);
    std::string NewString = "";
    for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
        snprintf(buf, 3, "%02x", hash[i]);
        NewString = NewString + buf;
    }
    return NewString;
}

int main(int argc, char **argv) {
    if (argc < 2)
    {
        printf("Please input file path\n");
        return -1;
    }
    std::string content;
    // std::ifstream infile;
    // infile.open(argv[1], std::ios::in | std::ios::binary);
    // if (!infile.is_open()) {
    //     printf("No such file\n");
    //     return -1;
    // }
    // std::ostringstream oss;
    // while (!infile.eof())
    // {
    //     oss << infile.rdbuf();
    // }
    // content = oss.str().c_str();
    // infile.close();
    for (size_t i = 0; i < atoi(argv[1]); i++)
    {
        content += "0";
    }
    std::ofstream outfile("my_file.txt", std::ios::out); 
    outfile << content;
    std::cout << content.size() << std::endl;
    auto pos1 = std::chrono::steady_clock::now();
    std::string hash1 = calc_hash_of_data_with_sha256(content.c_str());
    std::cout << hash1 << std::endl;
    auto pos2 = std::chrono::steady_clock::now();
    std::string hash2 = calc_hash_of_data_with_evp_sha256(content.c_str());
    std::cout << hash2 << std::endl;
    auto pos3 = std::chrono::steady_clock::now();
    std::chrono::duration<double> dur1 = pos2 - pos1;
    std::chrono::duration<double> dur2 = pos3 - pos2;
    std::cout << dur1.count() << "  " << dur2.count() << std::endl;
}